package com.fengmi.service;

import cn.hutool.core.collection.CollectionUtil;
import com.api.goods.GoodsApi;
import com.fengmi.dto.SearchDTO;
import com.fengmi.entity.ESGoods;
import com.fengmi.entity.MallWords;
import com.fengmi.goods.entity.MallGoods;
import com.fengmi.vo.PageResultVo;
import com.fengmi.vo.ResultVO;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.MatchQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.TermQueryBuilder;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.elasticsearch.search.suggest.Suggest;
import org.elasticsearch.search.suggest.SuggestBuilder;
import org.elasticsearch.search.suggest.SuggestBuilders;
import org.elasticsearch.search.suggest.completion.CompletionSuggestion;
import org.elasticsearch.search.suggest.completion.CompletionSuggestionBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Service
public class SearchService implements ISearchService{

//
//
//    @mysql2es
//    public  void  add(){
//        //insert into mysql
//
//
//
//    }
//    @mysql2es
//    public  void  update(){
//        //insert into mysql
//
//
//
//    }
//
//
//    @mysql2es
//    public  void  delete(){
//        //insert into mysql
//
//
//
//    }





    @Autowired
    private GoodsApi goodsApi;


    @Autowired
    private ElasticsearchRestTemplate restTemplate;

    @Override
    public ResultVO init() {


        //删除索引库
        restTemplate.deleteIndex(ESGoods.class);


        //创建索引库
        restTemplate.createIndex(ESGoods.class);

        restTemplate.putMapping(ESGoods.class);


        //远程调用goods服务获取商品信息
        List<MallGoods> goodsList = goodsApi.findGoodsHasAuditedForEs();

        //List<esgoods>
        List<ESGoods> esGoodsList = goodsList.stream().map(spu -> {
            ESGoods esGoods = new ESGoods();
            esGoods.setSpuId(spu.getSpuId());
            esGoods.setBrandId(spu.getBrand().getId());
            esGoods.setBrandName(spu.getBrand().getName());


            esGoods.setCat1id(spu.getCat1().getId());
            esGoods.setCat1name(spu.getCat1().getName());
            esGoods.setCat2id(spu.getCat2().getId());
            esGoods.setCat2name(spu.getCat2().getName());
            esGoods.setCat3id(spu.getCat3().getId());
            esGoods.setCat3name(spu.getCat3().getName());

            esGoods.setCreateTime(new Date());
            esGoods.setGoodsName(spu.getGoodsName());
            esGoods.setSale(spu.getSale()!=null?Long.parseLong(spu.getSale() + ""):0);
            esGoods.setPrice(spu.getPrice().doubleValue());

            esGoods.setImageUrl(spu.getAlbumPics());

            return esGoods;
        }).collect(Collectors.toList());


        //批量插入
        restTemplate.save(esGoodsList);

        return new ResultVO(true,"初始化成功");
    }

    @Override
    public PageResultVo<ESGoods> search(SearchDTO searchDTO) {

        //1：关键字搜索，match 三个field（goodsName，brandName，cat3Name）
        String keyword = searchDTO.getKeyword();
        BoolQueryBuilder bool = QueryBuilders.boolQuery();
        if(!StringUtils.isEmpty(keyword)){
            MatchQueryBuilder where1 = QueryBuilders.matchQuery("goodsName", keyword);
            MatchQueryBuilder where2 = QueryBuilders.matchQuery("brandName", keyword);
            MatchQueryBuilder where3 = QueryBuilders.matchQuery("cat3name", keyword);

            bool.should(where1).should(where2).should(where3);
            bool.minimumShouldMatch(1);
        }

        //2：设置分页
        PageRequest of = PageRequest.of(searchDTO.getPage() - 1, searchDTO.getSize());

        //3：设置高亮
        HighlightBuilder highlightBuilder = getHighlightBuilder("goodsName");


        //4：聚合
        TermsAggregationBuilder brandNameAgg = AggregationBuilders.terms("brandName_agg").field("brandName");
        TermsAggregationBuilder cat3nameAgg = AggregationBuilders.terms("cat3Name_agg").field("cat3name");


        //5：过滤
        //根据品牌名称过滤
        if(!StringUtils.isEmpty(searchDTO.getBrandNameFilter())){
            TermQueryBuilder brandNameFilter = QueryBuilders.termQuery("brandName", searchDTO.getBrandNameFilter());
            bool.filter(brandNameFilter)   ;
        }


        //根据三级分类过滤
        if(!StringUtils.isEmpty(searchDTO.getCat3NameFilter())){
            TermQueryBuilder cat3nameFilter = QueryBuilders.termQuery("cat3name", searchDTO.getCat3NameFilter());
            bool.filter(cat3nameFilter);
        }


        //根据is_delete进行过滤
        TermQueryBuilder not_delete = QueryBuilders.termQuery("is_delete", 0);
        bool.filter(not_delete);



        //6：排序功能
        String priceSort = searchDTO.getPriceSort();
        FieldSortBuilder priceSortBuilder = null;
        if("asc".equals(priceSort)){
            priceSortBuilder = SortBuilders.fieldSort("price").order(SortOrder.ASC);
        }
        if("desc".equals(priceSort)){
            priceSortBuilder = SortBuilders.fieldSort("price").order(SortOrder.DESC);
        }

        NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder()
                .withQuery(bool) //指定查询方式
                .withPageable(of) //设置分页
                .withHighlightBuilder(highlightBuilder) //设置高亮
                .addAggregation(brandNameAgg) //根据品牌名称进行分桶聚合
                .addAggregation(cat3nameAgg);

        if(priceSortBuilder != null){
            nativeSearchQueryBuilder.withSort(priceSortBuilder);
        }


        SearchHits<ESGoods> search = restTemplate.search(nativeSearchQueryBuilder.build(), ESGoods.class);

        List<SearchHit<ESGoods>> searchHits = search.getSearchHits();

        List<ESGoods> esGoodsList =
                searchHits.stream().map(item -> {
                    ESGoods content = item.getContent();
                    //取高亮
                    Map<String, List<String>> highlightFields = item.getHighlightFields();
                    List<String> goodsName = highlightFields.get("goodsName");
                    if(CollectionUtil.isNotEmpty(goodsName)){
                        content.setGoodsName(goodsName.get(0));
                    }
                    return content;
                }).collect(Collectors.toList());

        //获取聚合分桶的结果
        Aggregations aggregations = search.getAggregations();

        //获取品牌的聚合结果
        Terms brandName_agg = aggregations.get("brandName_agg");
        List<String> brandNameList = brandName_agg.getBuckets().stream().map(item -> (String) item.getKey()).collect(Collectors.toList());

        //获取三级分类的聚合结果
        Terms cat3Name_agg = aggregations.get("cat3Name_agg");
        List<String> cat3NameList = cat3Name_agg.getBuckets().stream().map(item -> (String) item.getKey()).collect(Collectors.toList());

        PageResultVo<ESGoods> pageResultVo = new PageResultVo<>();
        pageResultVo.setData(esGoodsList);
        pageResultVo.setTotal(search.getTotalHits());
        pageResultVo.setBrandList(brandNameList);
        pageResultVo.setCat3NameList(cat3NameList);
        return pageResultVo;
    }

    @Override
    public ResultVO<List> suggest(String tip) {
        CompletionSuggestionBuilder completionSuggestionBuilder = SuggestBuilders.
                completionSuggestion("words")
                .size(100)
                .skipDuplicates(true)
                .prefix(tip);

        SuggestBuilder suggestBuilder = new SuggestBuilder();
        suggestBuilder.addSuggestion("my-suggest", completionSuggestionBuilder);

        SearchResponse suggestResponse = restTemplate.suggest(suggestBuilder, restTemplate.getIndexCoordinatesFor(MallWords.class));

        Suggest suggest = suggestResponse.getSuggest();
        CompletionSuggestion completionSuggestion = suggest.getSuggestion("my-suggest");

        List<CompletionSuggestion.Entry> entries = completionSuggestion.getEntries();

        List<String> tips = new ArrayList<>();


        entries.forEach(item->{
            List<CompletionSuggestion.Entry.Option> options = item.getOptions();
            options.forEach(opt->{
                Text text = opt.getText();
                System.out.println(text.toString());
                tips.add(text.toString());
            });
        });

        return new ResultVO<>(true,"",tips);
    }


    // 设置高亮字段
    private HighlightBuilder getHighlightBuilder(String... fields) {
        // 高亮条件
        HighlightBuilder highlightBuilder = new HighlightBuilder(); //生成高亮查询器
        for (String field : fields) {
            highlightBuilder.field(field);//高亮查询字段
        }
        highlightBuilder.requireFieldMatch(false);     //如果要多个字段高亮,这项要为false
        highlightBuilder.preTags("<span style=\"color:red\">");   //高亮设置
        highlightBuilder.postTags("</span>");
        //下面这两项,如果你要高亮如文字内容等有很多字的字段,必须配置,不然会导致高亮不全,文章内容缺失等
        highlightBuilder.fragmentSize(800000); //最大高亮分片数
        highlightBuilder.numOfFragments(0); //从第一个分片获取高亮片段

        return highlightBuilder;
    }
}
